<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <style>
        html,
        body {
            margin: auto;
            width: 95%;
            font-size: 20px;
            text-align: center;
        }

        input {
            width: 3em;
        }

        button {
            width: 16em;
            height: 4em;
        }

        .controller {
            margin-top: 1em;
        }

        .quiz-item {
            width:25%; /* or whatever width you want. */
            max-width:25%; /* or whatever width you want. */
            display: inline-block;
            text-align: left;
            margin-top: 0.5em;
        }

    </style>
    <title>口算生成器</title>
</head>

<body>
    <h2 id="title">口算练习</h2>

    <div id="config" class="config">
        <table align="center">
            <thead>
                <tr>
                <th>题型</th> <th>数目</th>
                </tr>
            </thead>

            <tbody id="countmap">
            </tbody>
        </table>

        <button id="buttonGenerate">OK</button>
    </div>

    <div id="result" class="result">
    </div>

    <script>
        Array.prototype.shuffle = function() {
            var input = this;
            for (var i = input.length-1; i >=0; i--) {
                var randomIndex = Math.floor(Math.random()*(i+1));
                var itemAtIndex = input[randomIndex];
                input[randomIndex] = input[i];
                input[i] = itemAtIndex;
            }
            return input;
        }

        // Return rand int [start, end)
        function rand_int(start, end) {
            return parseInt(start + Math.random() * (end - start));
        }

        // 两位数乘一位数（不进位）
        function gen_category_01() {
            while (true) {
                var a = rand_int(1, 100);
                var b = rand_int(2, 10);

                if ((a > 10) &&             // 两位数
                    ((a % 10) != 0) &&      // 不是整十
                    ((a % 10) * b < 10) &&  // 不进位
                    (parseInt(a / 10) * b < 10)) {
                    return `${a}×${b}`;
                }
            }
        }

        // 两位数乘一位数（一次进位）
        function gen_category_02() {
            while (true) {
                var a = rand_int(1, 100);
                var b = rand_int(2, 10);

                if ((a > 10) &&             // 两位数
                    ((a % 10) != 0) &&      // 不是整十
                    ((a % 10) * b >= 10) &&  // 一次进位
                    (parseInt(a / 10) * b < 10)) {
                    return `${a}×${b}`;
                }
            }
        }

        // 带小数点的乘法
        function gen_category_021() {
            var a = rand_int(1, 100);
            var b = rand_int(2, 10);
            a = shiftDot(a, rand_int(-3, 3));
            b = shiftDot(b, rand_int(-3, 3));
            return `${a}x${b}`;
        }
        
        // 整十数、整百数乘一位数
        function gen_category_03() {
            while (true) {
                var a = rand_int(2, 10) * (10 ** rand_int(1, 3));
                var b = rand_int(2, 10);

                return `${a}×${b}`;
            }
        }
        
        // 整十数、整百数乘整十数
        function gen_category_04() {
            while (true) {
                var a = rand_int(2, 10);
                var b = rand_int(2, 10);
                var c = 10 ** rand_int(1, 3);

                return `${a * c}×${b * 10}`;
            }
        }

        // 整十数、整百数除以整十数
        function gen_category_05() {
            while (true) {
                var a = rand_int(2, 10)* (10 ** rand_int(1, 3));
                var b = rand_int(2, 10) * 10;

                if (a % b == 0) {
                    return `${a}\u00f7${b}`;
                }
            }
        }
        
        // 几百几十除以整十数(表内除法)
        function gen_category_06() {
            while (true) {
                var a = rand_int(2, 10);
                var b = rand_int(2, 10);
                var c = 10 ** rand_int(1, 3);

                return `${a * c * b}\u00f7${b * 10}`;
            }
        }

        // 两位数除以两位数（能整除）
        function gen_category_061() {
            while (true) {
                var a = rand_int(2, 10);
                var b = rand_int(10, 100);

                if (a * b < 100) {
                    return `${a * b}\u00f7${b}`;
                }
            }
        }

        // 带小数点的除法（能整除）
        function gen_category_062() {
            while (true) {
                var a = rand_int(2, 10);
                var b = rand_int(10, 100);

                a = a * b;
                // 移位
                a = shiftDot(a, rand_int(-3, 3));
                b = shiftDot(b, rand_int(-3, 3));

                return `${a}\u00f7${b}`;
            }
        }

        // 几百几十除以一位数（表内除法、首位能整除）
        function gen_category_07() {
            while (true) {
                var a = rand_int(2, 10);
                var b = rand_int(2, 10);

                if (a * b > 10) {
                    return `${a * b * 10}\u00f7${b}`;
                }
            }
        }

        // 两位数除以一位数（首位能整除且无余数）
        function gen_category_08() {
            while (true) {
                var a = rand_int(2, 100);
                var b = rand_int(2, 5);
                var c = a * b;

                if ((c > 10) &&
                    (c < 100) &&
                    (parseInt(c/10) % b == 0)) {
                    return `${c}\u00f7${b}`;
                }
            }
        }

        // 两位数除以一位数（首位不能整除且无余数）
        function gen_category_09() {
            while (true) {
                var a = rand_int(2, 100);
                var b = rand_int(2, 5);
                var c = a * b;

                if ((c > 10) &&
                    (c < 100) &&
                    (parseInt(c/10) % b != 0)) {
                    return `${c}\u00f7${b}`;
                }
            }
        }
        
        // 两位数加两位数（不进位）
        function gen_category_10() {
            while (true) {
                var a = rand_int(10, 100);
                var b = rand_int(10, 100);

                if ((a%10 + b%10 < 10) &&
                    (parseInt(a/10) + parseInt(b/10) < 10)) {
                    return `${a}+${b}`;
                }
            }
        }

        // 两位数加两位数（进位）
        function gen_category_11() {
            while (true) {
                var a = rand_int(10, 100);
                var b = rand_int(10, 100);

                if ((a%10 + b%10 >= 10) &&
                    (a+b<100)) {
                    return `${a}+${b}`;
                }
            }
        }

        // 两位数减两位数（不退位）
        function gen_category_12() {
            while (true) {
                var a = rand_int(10, 100);
                var b = rand_int(10, 100);
                var c = a + b;

                if ((a%10 + b%10 < 10) &&
                    (parseInt(a/10) + parseInt(b/10) < 10)) {
                    return `${c}-${b}`;
                }
            }
        }

        // 两位数减两位数（退位）
        function gen_category_13() {
            while (true) {
                var a = rand_int(10, 100);
                var b = rand_int(10, 100);
                var c = a + b;

                if ((a%10 + b%10 >= 10) && (c < 100)) {
                    return `${c}-${b}`;
                }
            }
        }


        // 整十数、整百数加整十数
        function gen_category_14() {
            while (true) {
                var a = rand_int(2, 100);
                var b = rand_int(2, 10);

                return `${a*10}+${b*10}`;
            }
        }

        // 整十数、整百数减整十数
        function gen_category_15() {
            while (true) {
                var a = rand_int(2, 100);
                var b = rand_int(2, 10);
                var c = a*10 + b*10;

                if (c < 1000) {
                    return `${c}-${b*10}`;
                }
            }
        }
        
        var tests = [
            {
                "text": "两位数乘一位数（不进位）",
                "generator": gen_category_01,
                "count": 4
            },
            {
                "text": "两位数乘一位数（一次进位）",
                "generator": gen_category_02,
                "count": 4
            },
            {
                "text": "带小数点的乘法",
                "generator": gen_category_021,
                "count": 6
            },
            {
                "text": "整十数、整百数乘一位数",
                "generator": gen_category_03,
                "count": 0
            },
            {
                "text": "整十数、整百数乘整十数",
                "generator": gen_category_04,
                "count": 0
            },
            {
                "text": "整十数、整百数除以整十数",
                "generator": gen_category_05,
                "count": 0
            },
            {
                "text": "几百几十数除以整十数",
                "generator": gen_category_05,
                "count": 4
            },
            {
                "text": "两位数除以两位数（能整除）",
                "generator": gen_category_061,
                "count": 4
            },
            {
                "text": "带小数点的除法（能整除）",
                "generator": gen_category_062,
                "count": 6
            },
            {
                "text": "几百几十除以一位数（表内除法、首位能整除）",
                "generator": gen_category_07,
                "count": 4
            },
            {
                "text": "两位数除以一位数（首位能整除且无余数）",
                "generator": gen_category_08,
                "count": 4
            },
            {
                "text": "两位数除以一位数（首位不能整除且无余数）",
                "generator": gen_category_09,
                "count": 4
            },
            {
                "text": "两位数加两位数（不进位）",
                "generator": gen_category_10,
                "count": 5
            },
            {
                "text": "两位数加两位数（进位）",
                "generator": gen_category_11,
                "count": 5
            },
            {
                "text": "两位数减两位数（不退位）",
                "generator": gen_category_12,
                "count": 5
            },
            {
                "text": "两位数减两位数（退位）",
                "generator": gen_category_13,
                "count": 5
            },
            {
                "text": "整十数、整百数加整十数",
                "generator": gen_category_14,
                "count": 4
            },
            {
                "text": "整十数、整百数减整十数",
                "generator": gen_category_15,
                "count": 4
            },
        ];

        function divide10(s) {
            s = `${s}`;
            var dotPos = s.indexOf(".");
            if (dotPos == -1) {
                if (s.length > 1) {
                    return s.substring(0, s.length - 1) + "." + s.substring(s.length-1);
                } else {
                    return "0." + s;
                }
            } else {
                if (dotPos == 1) {
                    return "0." + s.substring(0, 1) + s.substring(2);
                } else {
                    return s.substring(0, dotPos - 1) + "." + s.substring(dotPos-1, dotPos) + s.substring(dotPos + 1);
                }
            }
        }

        function shiftDot(v, pos) {
            v = `${v}`;
            while (pos < 0) {
                v = divide10(v);
                pos += 1;
            }
            while (pos > 0) {
                v = v + "0";
                pos -= 1;
            }
            return v;
        }

        function generateBatchQuiz() {
            data = new Set()

            tests.forEach(element => {
                for (var i = 0; i < element.count; i++) {
                    let ok = false;
                    while (!ok) {
                        let quiz = element.generator()
                        if (!data.has(quiz)) {
                            data.add(quiz)
                            ok = true
                        }
                    }
                }
            });
            return Array.from(data).shuffle()
        }

        function renderQuiz() {
            var data = generateBatchQuiz()
            var resultDiv = document.getElementById("result")
            resultDiv.innerHTML = ""
            data.forEach(item => {
                var d = document.createElement("span")
                d.innerHTML = item + "="
                d.setAttribute("class", "quiz-item")
                resultDiv.appendChild(d)
            })
        }

        function showConfig() {
            document.getElementById("config").style.display = "";
            document.getElementById("result").style.display = "none";

            // add text to the config table
            var countmap = document.getElementById("countmap")
            countmap.innerHTML = ""
            tests.forEach((item, index) => {
                var tr = document.createElement("tr")
                tr.innerHTML = `<td align="left">${item.text}</td><td><input type="number" id="cfg-${index}" label="cfg-${index}" value="${item.count}" min="0" max="20"/></td>`
                countmap.appendChild(tr)
            })
        }

        function refreshConfig() {
            tests.forEach((item, index) => {
                var td = document.getElementById(`cfg-${index}`)
                item.count = parseInt(td.value)
            })
        }

        showConfig()
        buttonGenerate.onclick = function() {
            document.getElementById("config").style.display = "none";
            document.getElementById("result").style.display = "";

            refreshConfig()
            renderQuiz()
        }
        document.getElementById("title").onclick = showConfig
        document.getElementById("result").onclick = renderQuiz
    </script>
</body>
